package xj.model.uml;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import xj.meta.ModelBuilder;
import xj.meta.ModelElement;
import xj.meta.ModelRepository;

import static xj.model.uml.UMLModelConstants.UML_MODEL_ADDER_NAMES;
import static xj.model.uml.UMLModelConstants.UML_MODEL_CLASSES;

/*
 * java  -classpath model.jar xj.model.uml.Main option file
 *
 * Options:
 *   -0: build a sample class diagram and save to file
 *   -1: build a sample use case diagram and save to file
 *   -2: build a sample sequence diagram and save to file
 *   -3: build a sample state diagram and save to file
 *   -4: build a sample activity diagram and save to file
 *   default: read file and dump model 
 */
public class Main {

  public static void main(String[] args) throws Exception {
    int i = 0;
    int mode = 0;
    String infile = null, outfile = null;

    for (i = 0; i < args.length; i++) {
      String arg = args[i];
      if (arg.charAt(0) == '-') {
	mode = (arg.charAt(1) - '0');
      } else {
	if (mode >= 0 && mode <= 4) {
	  if (outfile == null) {
	    outfile = arg;
	  }
	} else {
	  if (infile == null) {
	    infile = arg;
	  } else if (outfile == null) {
	    outfile = arg;
	  }
	}
      }
    }

    PrintWriter out;
    if (outfile != null) {
      out = new PrintWriter(new BufferedWriter(new FileWriter(outfile)));
    } else {
      out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    }

    ModelRepository rep = ModelRepository.getInstance();
    switch (mode) {
    case 0:
      makeClassDiagram(rep);
      break;
    case 1:
      makeUseCaseDiagram(rep);
      break;
    case 2:
      makeSequenceDiagram(rep);
      break;
    case 3:
      makeStateDiagram(rep);
      break;
    case 4:
      makeActivityDiagram(rep);
      break;

    default:
      if (infile != null) {
	ModelBuilder.addElements(UML_MODEL_CLASSES);
	ModelBuilder.addAdderNames(UML_MODEL_ADDER_NAMES);
	ModelElement root = ModelBuilder.loadModelFile(infile);
	if (root != null) {
	  rep.setRoot(root);
	}
      }
    }
    rep.dump();
    rep.exportXML(out);
    out.flush();
    out.close();
  }

  public static void makeClassDiagram(ModelRepository rep) {
    UMLModel model = new UMLModel("UMLProject1");
    ClassDiagram cd = new ClassDiagram("ClassDiagram1");
    model.addUMLDiagram(cd);

    UMLClass c1 = new UMLClass("MyClass1");
    c1.addSuperType(new SuperType("A"));
    c1.addSuperType(new SuperType("B"));
    c1.addAttribute(new Attribute("x", "int", Visibility.Protected));
    c1.addAttribute(new Attribute("s", "String"));
    Operation m1 = new Operation("m1", "void", Visibility.Public);
    c1.addOperation(m1);
    Operation m2 = new Operation("m2", "String", Visibility.Public);
    m2.addParameter(new Parameter("a", "double"));
    m2.addParameter(new Parameter("b", "double"));
    c1.addOperation(m2);
    c1.addStereotype("st1");
    c1.addStereotype("st2");
    c1.setTagValue("t1", "v1");
    c1.setTagValue("t2", "v2");
    c1.addComment(new Comment("a comment"));
    c1.addConstraint(new Constraint("x > y & limit < 100"));

    cd.addUMLClass(c1);

    UMLClass c2 = new UMLClass("MyClass2");
    cd.addUMLClass(c2);

    UMLClass c3 = new UMLClass("MyClass3");
    cd.addUMLClass(c3);

    UMLAssociation assoc = new UMLAssociation("comp",
					      UMLAssociation.AssociationType.Composition, 
					      c2, 
					      new UMLAssociationEnd("role1", Multiplicity.toMultiplicity("1")), 
					      c3,
					      new UMLAssociationEnd("role2", Multiplicity.toMultiplicity("*")));
    cd.addUMLAssociation(assoc);

    UMLPackage pkg1 = new UMLPackage("xj.meta");
    cd.addUMLPackage(pkg1);

    UMLPackage pkg2 = new UMLPackage("xj.meta.pkg");
    pkg1.addUMLPackage(pkg2);
    UMLClass c4 = new UMLClass("MyClass4");
    pkg1.addUMLClass(c4);

    rep.setRoot(model);
    rep.addRelation("Assoc");
    rep.addAssociationElement("Assoc", assoc);
  }

  public static void makeUseCaseDiagram(ModelRepository rep) {
    UMLModel model = new UMLModel("UMLProject2");
    UseCaseDiagram ucd = new UseCaseDiagram("UseCaseDiagram1");
    model.addUMLDiagram(ucd);

    UseCase u1 = new UseCase("UseCase1");
    ucd.addUseCase(u1);
    UseCase u2 = new UseCase("UseCase2");
    ucd.addUseCase(u2);
    UseCase u3 = new UseCase("UseCase3");
    ucd.addUseCase(u3);

    Actor a1 = new Actor("Actor1");
    ucd.addActor(a1);
    Actor a2 = new Actor("Actor2");
    ucd.addActor(a2);
    Actor a3 = new Actor("Actor3");
    ucd.addActor(a3);

    UMLAssociation e1 = new UMLAssociation(
	UMLAssociation.AssociationType.Generalization, a1, a2);
    ucd.addUMLAssociation(e1);
    UMLAssociation e2 = new UMLAssociation(
	UMLAssociation.AssociationType.Generalization, a1, a3);
    ucd.addUMLAssociation(e2);

    UMLAssociation s1 = new UMLAssociation(
	UMLAssociation.AssociationType.Association, a1, u1);
    ucd.addUMLAssociation(s1);
    UMLAssociation s2 = new UMLAssociation(
	UMLAssociation.AssociationType.Association, a1, u2);
    ucd.addUMLAssociation(s2);
    UMLAssociation s3 = new UMLAssociation(
	UMLAssociation.AssociationType.Association, a2, u2);
    ucd.addUMLAssociation(s3);
    UMLAssociation s4 = new UMLAssociation(
	UMLAssociation.AssociationType.Association, a3, u3);
    ucd.addUMLAssociation(s4);

    rep.setRoot(model);
  }

  public static void makeSequenceDiagram(ModelRepository rep) {
    UMLModel model = new UMLModel("UMLProject3");
    SequenceDiagram sd = new SequenceDiagram("SequenceDiagram1");
    model.addUMLDiagram(sd);

    UMLObject o1 = new UMLObject("Object1");
    sd.addUMLObject(o1);
    UMLObject o2 = new UMLObject("Object2");
    sd.addUMLObject(o2);
    UMLObject o3 = new UMLObject("Object3");
    sd.addUMLObject(o3);

    LifeLine l1 = new LifeLine("l1", o1);
    sd.addLifeLine(l1);
    LifeLine l2 = new LifeLine("l2", o2);
    sd.addLifeLine(l2);
    LifeLine l3 = new LifeLine("l3", o3);
    sd.addLifeLine(l3);

    ExecutionOccurance e11 = new ExecutionOccurance("e11", o1);
    e11.setInterval(1, 10);
    l1.addExecutionOccurance(e11);
    ExecutionOccurance e12 = new ExecutionOccurance("e12", o1);
    e12.setInterval(15, 20);
    l1.addExecutionOccurance(e12);

    ExecutionOccurance e21 = new ExecutionOccurance("e21", o2);
    e21.setInterval(5, 15);
    l2.addExecutionOccurance(e21);

    ExecutionOccurance e31 = new ExecutionOccurance("e31", o3);
    e31.setInterval(20, 25);
    l3.addExecutionOccurance(e31);

    UMLMessage m1 = new UMLMessage(UMLMessage.MessageType.Synchorous_Call, e11,
	e21);
    m1.setStart(5);
    sd.addUMLMessage(m1);

    UMLMessage m2 = new UMLMessage(UMLMessage.MessageType.Synchorous_Call, e21,
	e31);
    m2.setStart(15);
    sd.addUMLMessage(m2);

    rep.setRoot(model);
  }

  public static void makeStateDiagram(ModelRepository rep) {
    UMLModel model = new UMLModel("UMLProject4");
    StateDiagram sd = new StateDiagram("StateDiagram1");
    model.addUMLDiagram(sd);

    State s0 = new State("s0", State.StateType.Initial_State);
    sd.addState(s0);

    State s1 = new State("s1", State.StateType.Simple_State);
    sd.addState(s1);

    State s2 = new State("s2", State.StateType.Final_State);
    sd.addState(s2);

    HyperState s3 = new HyperState("s3");
    sd.addState(s3);
    State s31 = new State("s31", State.StateType.Simple_State);
    s3.addState(s31);
    State s32 = new State("s32", State.StateType.Simple_State);
    s3.addState(s32);

    OrthogonalState s4 = new OrthogonalState("s4");
    sd.addState(s4);

    Transition t1 = new Transition(s0, s1);
    t1.setEventName("e1");
    sd.addTransition(t1);
    Transition t2 = new Transition(s1, s2);
    t2.setEventName("e2");
    t2.setGuardText("g2");
    sd.addTransition(t2);

    rep.setRoot(model);
  }

  public static void makeActivityDiagram(ModelRepository rep) {
    UMLModel model = new UMLModel("UMLProject5");
    ActivityDiagram ad = new ActivityDiagram("ActivityDiagram1");
    model.addUMLDiagram(ad);

    ActivityNode n1 = new ActivityNode("n1", ActivityNode.ActivityType.Initial);
    ad.addActivityNode(n1);
    ActivityNode n2 = new ActivityNode("n2",
	ActivityNode.ActivityType.Computation);
    ad.addActivityNode(n2);
    ActivityNode n3 = new ActivityNode("n3", ActivityNode.ActivityType.Final);
    ad.addActivityNode(n3);

    ActivityFlow f1 = new ActivityFlow(n1, n2);
    ad.addActivityFlow(f1);
    ActivityFlow f2 = new ActivityFlow(n2, n3);
    ad.addActivityFlow(f2);

    rep.setRoot(model);
  }

}
